home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch03 / linecalc.c < prev    next >
C/C++ Source or Header  |  1993-05-21  |  12KB  |  419 lines

  1. /****************************************************************
  2. * FILE:    linecalc.c
  3. * DESC:    These routines include the warping calculations and
  4. *        the line-handling functions.
  5. * HISTORY:    Created      3/11/1993
  6. * LAST CHANGED:  5/ 6/1993
  7. *    Copyright (c) 1993 by Scott Anderson
  8. *
  9. ****************************************************************/
  10.  
  11. /* ----------------------INCLUDES----------------------------- */
  12.  
  13. #include <conio.h>
  14. #include <stdio.h>
  15. #include <io.h>
  16. #include <math.h>
  17. #include <graph.h>
  18.  
  19. #include <malloc.h>
  20. #include <memory.h>
  21. #include <string.h>
  22.  
  23. #include "define.h"
  24.  
  25. /* -----------------------MACROS------------------------------ */
  26.  
  27. #define PIXEL(p,x,y)    (p->pixmap[y * (long) p->wide + x])
  28. #define SQUARE(x)         (((long) x)*(x))
  29.  
  30. /* ----------------------PROTOTYPES--------------------------- */
  31.  
  32. /**** line routines ****/
  33. int        xorLine(int x1, int y1, int x2, int y2);
  34. int        getLine(int *argx1, int *argy1, int *argx2, int *argy2);
  35. int        findPoint(LINE_LIST *lineList, int * line, int * point,
  36.                                                 int x, int y);
  37. int        movePoint();
  38.  
  39. /**** warping and morphing routines ****/
  40. int        sumLines(PICTURE *picture, COLOR *color, LINE *origline,
  41.                                     POINT *warp, LINE *warpline);
  42. float    getSourceLoc(POINT *orig, LINE *origline, POINT *warp,
  43.                                     LINE *warpline);
  44. int        setLength(LINE *line);
  45.  
  46. void    setupScreen(PICTURE *pic, int editFlag);
  47.  
  48. /* ----------------------EXTERNALS---------------------------- */
  49.  
  50. /* set from last picture loaded */
  51. extern int        Xmin, Ymin, Xmax, Ymax;
  52.  
  53. extern int        NumLines;
  54.  
  55. extern LINE        SrcLine[MAX_LINES];
  56. extern LINE        DstLine[MAX_LINES];
  57.  
  58. /* ----------------------GLOBAL DATA-------------------------- */
  59.  
  60. int        TargFlag=0;
  61.  
  62. /********   These are the basic warping calculations   **********/
  63.  
  64. /*****************************************************************
  65. * FUNC: int    sumLines(PICTURE *picture, COLOR *color,
  66. *                    LINE *origline, POINT *warp, LINE *warpline)
  67. * DESC: Sum and weight the contribution of each warping line
  68. *****************************************************************/
  69.  
  70. int
  71. sumLines(PICTURE *picture, COLOR *color, LINE *origline,
  72.                                     POINT *warp, LINE *warpline)
  73. {
  74.     int        x, y;
  75.     float    weight, weightSum;
  76.     float    distance;
  77.     int        line;
  78.     POINT    orig;
  79.     int        paletteIndex;
  80.     float    deltaSumX = 0.0;
  81.     float    deltaSumY = 0.0;
  82.  
  83.     /* if no control lines, get an unwarped pixel */
  84.     if (NumLines == 0)
  85.         orig = *warp;
  86.     else {
  87.         weightSum = 0.0;
  88.         for (line = 0; line < NumLines; line++,
  89.                             origline++, warpline++)    {
  90.             distance = getSourceLoc(&orig,origline,warp,warpline);
  91.             weight = 1/(.001+distance*distance);
  92.             deltaSumX += (orig.x - warp->x) * weight;
  93.             deltaSumY += (orig.y - warp->y) * weight;
  94.             weightSum += weight;
  95.         }
  96.         orig.x = warp->x + deltaSumX / weightSum + .5;
  97.         orig.y = warp->y + deltaSumY / weightSum + .5;
  98.     }
  99.  
  100.     /* clip it to the nearest border pixel */
  101.     x = clip(orig.x, Xmin, Xmax);
  102.     y = clip(orig.y, Ymin, Ymax);
  103.     paletteIndex = PIXEL (picture, x, y);
  104.     color->r = picture->pal.c[paletteIndex].r;
  105.     color->g = picture->pal.c[paletteIndex].g;
  106.     color->b = picture->pal.c[paletteIndex].b;
  107.     return (paletteIndex);
  108. }
  109.  
  110. /*****************************************************************
  111. * FUNC: float getSourceLoc(POINT *orig, LINE *origline,
  112. *                                    POINT *warp, LINE *warpline)
  113. * DESC: For a given line, locate the corresponding warped pixel
  114. *****************************************************************/
  115.  
  116. float
  117. getSourceLoc(POINT *orig, LINE *origline, POINT *warp,
  118.                                                 LINE *warpline)
  119. {
  120.     float fraction, fdist;
  121.     int dx, dy;
  122.     float distance;
  123.  
  124.     dx = warp->x - warpline->p[0].x;
  125.     dy = warp->y - warpline->p[0].y;
  126.     fraction = (dx * (long) warpline->delta_x + dy
  127.                 * (long) warpline->delta_y)
  128.                 / (float) (warpline->length_square);
  129.     fdist = (dx * (long) -warpline->delta_y + dy
  130.                 * (long) warpline->delta_x)
  131.                 / (float) warpline->length;
  132.     if (fraction <= 0 )
  133.         distance = sqrt(dx*(long) dx + dy * (long) dy);
  134.     else if (fraction >= 1) {
  135.         dx = warp->x - warpline->p[1].x;
  136.         dy = warp->y - warpline->p[1].y;
  137.         distance = sqrt(dx*(long) dx + dy * (long) dy);
  138.     }                 
  139.     else if (fdist >= 0)
  140.         distance =  fdist;
  141.     else
  142.         distance = -fdist;
  143.     orig->x = origline->p[0].x + fraction * origline->delta_x -
  144.                 fdist * origline->delta_y
  145.                 / (float) origline->length + .5;
  146.     orig->y = origline->p[0].y + fraction * origline->delta_y +
  147.                 fdist * origline->delta_x
  148.                 / (float) origline->length + .5;
  149.     return distance;
  150. }
  151.  
  152. /*****************************************************************
  153. * FUNC: int    setLength(LINE *line)
  154. * DESC: Set the deltas, the length and the length squared
  155. *        for a given line.
  156. *****************************************************************/
  157.  
  158. int
  159. setLength (LINE *line)
  160. {
  161.     line->delta_x = line->p[1].x - line->p[0].x;
  162.     line->delta_y = line->p[1].y - line->p[0].y;
  163.     line->length_square = SQUARE(line->delta_x)
  164.                         + SQUARE(line->delta_y);
  165.     line->length = sqrt(line->length_square);
  166. }
  167.  
  168. /*********************  The line routines  **********************/
  169.  
  170. /*****************************************************************
  171. * FUNC: int    xorLine(int x1, int y1, int x2, int y2)
  172. * DESC: Draw a line on the screen using the XOR of the
  173. *        screen index.
  174. *****************************************************************/
  175.  
  176. int
  177. xorLine(int x1, int y1, int x2, int y2)
  178. {
  179.     int oldcolor = _getcolor();
  180.  
  181.     _setcolor(WHITE);            /* Use white as the xor color */
  182.     _setwritemode(_GXOR);
  183.     _moveto (x1,y1);
  184.     _lineto (x2,y2);
  185.     _setcolor(oldcolor);    /* restore the old color */
  186. }
  187.  
  188. /*****************************************************************
  189. * FUNC: int    getLine(int *argx1, int *argy1, int *argx2, int*argy2)
  190. * DESC: Input a line on the screen with the mouse.
  191. *****************************************************************/
  192.  
  193. int
  194. getLine (int *argx1, int *argy1, int *argx2, int *argy2)
  195. {
  196.     int        x1,y1, x2,y2;
  197.     int        oldx, oldy;
  198.     int        input;
  199.  
  200.     /* save the current mode */
  201.     short    old_mode = _getwritemode();
  202.  
  203.     /* get input until we have a real line, not just a point */
  204.     do {
  205.         /* wait for button or key press */
  206.         while (!(input = mousePos (&x1, &y1)));
  207.         if (input & KEYPRESS) {
  208.             _setwritemode(old_mode);
  209.             return 1;
  210.         }
  211.         oldx=x1, oldy=y1;
  212.         hideMouse();
  213.         /* prime the pump with this dot */
  214.         xorLine (x1, y1, oldx, oldy);
  215.         showMouse();
  216.         while (input = mousePos (&x2, &y2)) {
  217.             /* rubber band a line while the mouse is dragged */
  218.             if (x2 != oldx || y2 != oldy)
  219.             {
  220.                 hideMouse();
  221.                 xorLine (x1, y1, oldx, oldy);
  222.                 xorLine (x1, y1, x2, y2);
  223.                 showMouse();
  224.                 oldx=x2, oldy=y2;
  225.             }
  226.         }
  227.     } while (x1 == x2 && y1 == y2);
  228.  
  229.     *argx1 = x1, *argy1 = y1;
  230.     *argx2 = x2, *argy2 = y2;
  231.  
  232.     _setwritemode(old_mode);        /* get out of XOR mode */
  233.     return (0);
  234. }
  235.  
  236. /*****************************************************************
  237. * FUNC: int    findPoint(LINE_LIST *lineList, int * line,
  238. *        int * point, int x, int y)
  239. * DESC: loop thru dstline and find point within GRAB_DISTANCE,
  240. *        return 1 if found, 0 otherwise.
  241. *****************************************************************/
  242.  
  243. int
  244. findPoint (LINE_LIST *lineList, int * line, int * point,
  245.                                                     int x, int y)
  246. {
  247.     int l, p;
  248.     int minl, minp;
  249.     long length;
  250.     long minlength = SQUARE(640) + SQUARE(480);
  251.  
  252.     for (l = 0; l < lineList->number; l++) {
  253.         for (p = 0; p <= 1; p++) {
  254.             length = SQUARE(lineList->line[l].p[p].x - x)
  255.                    + SQUARE(lineList->line[l].p[p].y - y);
  256.             if (length < minlength) {
  257.                 minlength = length;
  258.                 minl = l;
  259.                 minp = p;
  260.             }
  261.         }
  262.     }
  263.     if (minlength > GRAB_DISTANCE)
  264.         return 0;
  265.     *line = minl;
  266.     *point = minp;
  267.     return 1;
  268. }
  269.  
  270. /*****************************************************************
  271. * FUNC: int    movePoint(LINE_LIST *lineList)
  272. * DESC: Grab a point and move it. Return 1 when key is pressed,
  273. *        else return 0.
  274. *****************************************************************/
  275.  
  276. int
  277. movePoint(LINE_LIST *lineList)
  278. {
  279.     int        stuckx, stucky, movex,movey;
  280.     int        oldx, oldy;
  281.     int        input;
  282.     int     line, point;
  283.  
  284.     /* save the current mode */
  285.     short    old_mode = _getwritemode();
  286.  
  287.     do {
  288.         /* keep getting input until we have a mouse button */
  289.         while (!(input = mousePos (&movex, &movey)));
  290.         if (input & KEYPRESS) {
  291.             _setwritemode(old_mode);
  292.             return 1;
  293.         }
  294.         if (!findPoint(lineList, &line, &point, movex, movey)) {
  295.             _setwritemode(old_mode);
  296.             return 0;
  297.         }
  298.  
  299.         /* establish fixed end point */
  300.         stuckx = lineList->line[line].p[1-point].x;
  301.         stucky = lineList->line[line].p[1-point].y;
  302.  
  303.         oldx=movex, oldy=movey;
  304.         hideMouse();
  305.         /* erase the old line */
  306.         xorLine (stuckx,
  307.                 stucky,
  308.                 lineList->line[line].p[point].x,
  309.                 lineList->line[line].p[point].y);
  310.         /* and prime the pump with the new line */
  311.         xorLine (stuckx, stucky, oldx, oldy);
  312.         showMouse();
  313.  
  314.         while (input = mousePos (&movex, &movey)) {
  315.             /* rubber band a line while the mouse is dragged */
  316.             if (movex != oldx || movey != oldy) {
  317.                 hideMouse();
  318.                 xorLine (stuckx, stucky, oldx, oldy);
  319.                 xorLine (stuckx, stucky, movex, movey);
  320.                 showMouse();
  321.                 oldx=movex, oldy=movey;
  322.             }
  323.         }
  324.     } while (stuckx == movex && stucky == movey);
  325.  
  326.     lineList->line[line].p[point].x = movex;
  327.     lineList->line[line].p[point].y = movey;
  328.  
  329.     _setwritemode(old_mode);        /* get out of XOR mode */
  330.     return (0);
  331. }
  332.  
  333. /*****************************************************************
  334. * FUNC: void    createLines(PICTURE *pic, LINE_LIST *lineList)
  335. * DESC: create a list of line segments for a picture
  336. *****************************************************************/
  337.  
  338. void
  339. createLines(PICTURE *pic, LINE_LIST *lineList)
  340. {
  341.     setupScreen(pic, 0);    /* set for enter prompt */
  342.  
  343.     initMouse();
  344.     showMouse();
  345.     for (lineList->number = 0;lineList->number < MAX_LINES;
  346.                                         lineList->number++) {
  347.         if (getLine(&lineList->line[lineList->number].p[0].x,
  348.                     &lineList->line[lineList->number].p[0].y,
  349.                     &lineList->line[lineList->number].p[1].x,
  350.                     &lineList->line[lineList->number].p[1].y))
  351.             break;
  352.     }
  353.     hideMouse();
  354. }
  355.  
  356.  
  357. /*****************************************************************
  358. * FUNC: void    editLines(PICTURE *pic, LINE_LIST *lineList)
  359. * DESC: move around some existing lines
  360. *****************************************************************/
  361.  
  362. void
  363. editLines(PICTURE *pic, LINE_LIST *lineList)
  364. {
  365.     int segment;
  366.  
  367.     setupScreen(pic, 1);    /* set for edit prompt */
  368.  
  369.     initMouse();
  370.     for (segment = 0; segment < lineList->number; segment++) {
  371.         xorLine(lineList->line[segment].p[0].x,
  372.                 lineList->line[segment].p[0].y,
  373.                 lineList->line[segment].p[1].x,
  374.                 lineList->line[segment].p[1].y);
  375.     }
  376.     showMouse();
  377.     /* move the endpoints around */
  378.     while(!movePoint(lineList));
  379.     hideMouse();
  380. }
  381.  
  382. /*****************************************************************
  383. * FUNC: void    setupScreen(PICTURE *pic, int editFlag)
  384. * DESC: Print a message introducing the screen, wait for input,
  385. *        then set the graphics mode and display the screen.
  386. *****************************************************************/
  387.  
  388. void
  389. setupScreen(PICTURE *pic, int editFlag)
  390. {
  391.     static char *editMess[2] = {"enter", "edit"};
  392.     static char *targMess[2] = {"source", "target"};
  393.     setTextMode();
  394.  
  395.     _settextposition(VTAB, HTAB);
  396.     printf("When you are ready to %s the control lines",
  397.             editMess[editFlag]);
  398.     _settextposition(VTAB+2, HTAB);
  399.     printf("for the %s image, press any key.",
  400.             targMess[TargFlag]);
  401.     waitForKey();
  402.  
  403.     setGraphicsMode();
  404.     displayPicture(pic);
  405. }
  406.  
  407.